package redis

import (
    "encoding/json"
    "net"
    "time"
    "fmt"
    "github.com/garyburd/redigo/redis"

    "xlq-demo/library/config"
    "xlq-demo/library/logger"
)

type Config struct {
    Host      string
    Password  string
    MaxIdle   int
    MaxActive int
    Prefix    string
    Db        int
}

var redisCache *redis.Pool
var redisPrefix string

func Initial() {
    fmt.Println("initial redis ...")
    config := &Config{
        Host:         config.Config.Redis.Host,
        Password:     config.Config.Redis.Psd,
        MaxIdle:         config.Config.Redis.Maxidle,
        MaxActive:     config.Config.Redis.MaxActive,
        Prefix:     config.Config.Redis.KeyPrefix,
        Db: config.Config.Redis.Db,
    }
    redisPrefix = config.Prefix
    redisCache = &redis.Pool{
        MaxIdle:     config.MaxIdle,
        MaxActive:   config.MaxActive,
        IdleTimeout: 180 * time.Second,
        Dial: func() (redis.Conn, error) {
            c, err := redis.Dial("tcp", config.Host)
            if err != nil {
                fmt.Println(err.Error())
                panic(-1)
            }
            if config.Password != "" {
                if _, err := c.Do("AUTH", config.Password); err != nil {
                    fmt.Println(err.Error())
                    panic(-1)
                }
            }
            c.Do("SELECT",config.Db)

            return c, nil
        },
    }
    Ping(config.Host)
}

// Ping
func Ping(host string) {
    conn, err := net.DialTimeout("tcp", host, 3*time.Second)
    if err != nil {
        logger.Warn(err.Error())
        panic(-1)
    }
    defer conn.Close()
}

// GetPool 获取一个连接
func GetPool() redis.Conn{
    return redisCache.Get()
}

// 删除
func Remove(name string) error {
    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    rc := redisCache.Get()
    defer rc.Close()
    _, err := rc.Do("DEL", key)
    if err != nil {
        logger.Warn(err.Error())
        return err
    }
    return nil
}

// 保存引用类型
func Save(name string, values interface{}) error {
    rc := redisCache.Get()
    defer rc.Close()

    serialized, err := json.Marshal(values)
    if err != nil {
        logger.Warn(err.Error())
        return err
    }
    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    _, err = rc.Do("SET", key, serialized)
    if err != nil {
        logger.Warn(err.Error())
        return err
    }
    return nil
}

// 获取引用类型
func Get(name string, values interface{}) error {
    rc := redisCache.Get()
    defer rc.Close()
    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    value, err := redis.Bytes(rc.Do("GET", key))
    if  err != nil {
        logger.Warn(key, err.Error())
        return err
    }

    err = json.Unmarshal(value, &values)
    if err != nil {
        logger.Warn(key, err.Error())
        return err
    }
    return nil
}

// 设置超时 单位为秒
func SetEx(name string,values interface{},ex int64) error {
    rc := redisCache.Get()
    defer rc.Close()

    serialized, err := json.Marshal(values)
    if err != nil {
        logger.Warn(err.Error())
        return err
    }
    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    _, err = rc.Do("SET", key, serialized,"ex",ex)
    if err != nil {
        logger.Warn(err.Error())
        return err
    }
    return nil
}

//设置字符串
func SaveString(name,value string) error  {
    rc := redisCache.Get()
    defer rc.Close()

    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    _, err := rc.Do("SET", key, value)
    if err != nil {
        logger.Warn(err.Error())
        return err
    }
    return nil
}
//获取字符串
func GetString(name string) (string,error) {
    rc := redisCache.Get()
    defer rc.Close()
    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    value, err := redis.Bytes(rc.Do("GET", key))
    if  err != nil {
        logger.Warn(key, err.Error())
        return "",err
    }

    return string(value),nil
}
//设置字符串超时
func SetExString(name string,value string,ex int64) error {
    rc := redisCache.Get()
    defer rc.Close()

    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    _, err := rc.Do("SET", key, value,"ex",ex)
    if err != nil {
        logger.Warn(err.Error())
        return err
    }
    return nil
}

//获取键的有效时间 秒数
func Ttl(name string) (int,error) {
    rc := redisCache.Get()
    defer rc.Close()

    key := fmt.Sprintf("%s:%s", redisPrefix, name)
    res, err := redis.Int(rc.Do("TTL", key))
    if err != nil {
        logger.Warn(err.Error())
        return 0,err
    }
    return res,nil
}